#include <stdio.h>
#include <string>

// copied from ex05gb
class logger
{
public:
	logger(const std::string &path);
	~logger();
	void log(const std::string &s);
};

class server_connection;

// [[ex05ha]]
// DEBUG descr An explicit context replaces a set of singletons.
struct server_context
{
	server_connection *conn_;
	logger *logger_;

	// the constructor takes over the ownership
	// DEBUG getfrom server_context
	server_context(server_connection *conn, logger *logger);
	~server_context();
	// DEBUG endget

private:
	server_context(); // no default constructor
	server_context(const server_context &);
	void operator=(const server_context &);
};
// END

// [[ex05hb]]
// DEBUG descr Usage of an explicit context structure.
class server_connection
{
public:
	server_connection() :
		log_(0) //, ...
	{
		// ...
	}
	~server_connection()
	{
		close();
		// ...
	}

	void setlogger(logger *log)
	{
		log_ = log;
	}

	void open(const std::string &address) 
	{
		// ...
		log("server_connection opened connection to "
			+ address);
	}
	void close();

protected:
	void log(const std::string &s)
	{
		if (log_)
			log_->log(s);
	}

	logger *log_;
	// ...
};
// DEBUG move server_context
	/*DEBUG{*/server_context::/*}DEBUG*/server_context(
			server_connection *conn, logger *logger) :
		conn_(conn), logger_(logger)
	{
		conn_->setlogger(logger);
	}

	/*DEBUG{*/server_context::/*}DEBUG*/~server_context()
	{
		delete conn_;
		delete logger_;
	}
// DEBUG endmove server_context

// DEBUG {
class bar
{
public:
	bar(logger *log); // sets log_

	void do_bar(int x)
	{
		// ...
		log_->log(
			"error: bad parameters to method bar::bar()");
		// ...
	}

protected:
	logger *log_;
};

void baz(logger *log, int x)
{
	// ...
	log->log("error: bad parameters to function baz()");
	// ...
}

// DEBUG }
class foo
{
public:
	foo(server_context *ctx); // sets ctx_

	void do_foo(int a, int b)
	{
		// ...
		ctx_->logger_->log(
			"error: bad parameters to method foo::foo()");
		// ...
		bar mybar(ctx_->logger_);
		mybar.do_bar(b);
		// ...
	}

protected:
	server_context *ctx_;
};

int main(int argc, char **argv)
{
	server_context *ctx = new server_context(
		new server_connection,
		new logger(argc > 1? argv[1] : "/tmp/log")
	);
	// ...
	ctx->conn_->open(argc > 2? argv[2] : "my_server");
	// ...
	foo myfoo(ctx);
	// ...
	myfoo.do_foo(1, 2);
	baz(ctx->logger_, 3);
	// ...
	delete ctx;
	return 0;
}
// END

// DEBUG {
void logger::log(const std::string &s)
{
	fprintf(stderr, "%s\n", s.c_str());
}
logger::logger(const std::string &path)
{
	fprintf(stderr, "logger instance created and opened\n");
}
logger::~logger()
{
	fprintf(stderr, "logger instance destroyed\n");
}

void server_connection::close() 
{
	log("server_connection closed connection");
}

foo::foo(server_context *ctx) :
	ctx_(ctx)
{ }

bar::bar(logger *log) :
	log_(log)
{ }
// DEBUG }

/* Sample output:
logger instance created and opened
server_connection opened connection to my_server
error: bad parameters to method foo::foo()
error: bad parameters to method bar::bar()
error: bad parameters to function baz()
server_connection closed connection
logger instance destroyed

*/
